1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import com.google.common.annotations.GwtCompatible;
20  
21  import java.io.Serializable;
22  import java.util.Collection;
23  import java.util.EnumSet;
24  
25  /**
26   * Implementation of {@link ImmutableSet} backed by a non-empty {@link
27   * java.util.EnumSet}.
28   *
29   * @author Jared Levy
30   */
31  @GwtCompatible(serializable = true, emulated = true)
32  @SuppressWarnings("serial") // we're overriding default serialization
33  final class ImmutableEnumSet<E extends Enum<E>> extends ImmutableSet<E> {
34    static <E extends Enum<E>> ImmutableSet<E> asImmutable(EnumSet<E> set) {
35      switch (set.size()) {
36        case 0:
37          return ImmutableSet.of();
38        case 1:
39          return ImmutableSet.of(Iterables.getOnlyElement(set));
40        default:
41          return new ImmutableEnumSet<E>(set);
42      }
43    }
44  
45    /*
46     * Notes on EnumSet and <E extends Enum<E>>:
47     *
48     * This class isn't an arbitrary ForwardingImmutableSet because we need to
49     * know that calling {@code clone()} during deserialization will return an
50     * object that no one else has a reference to, allowing us to guarantee
51     * immutability. Hence, we support only {@link EnumSet}.
52     */
53    private final transient EnumSet<E> delegate;
54  
55    private ImmutableEnumSet(EnumSet<E> delegate) {
56      this.delegate = delegate;
57    }
58  
59    @Override boolean isPartialView() {
60      return false;
61    }
62  
63    @Override public UnmodifiableIterator<E> iterator() {
64      return Iterators.unmodifiableIterator(delegate.iterator());
65    }
66  
67    @Override
68    public int size() {
69      return delegate.size();
70    }
71  
72    @Override public boolean contains(Object object) {
73      return delegate.contains(object);
74    }
75  
76    @Override public boolean containsAll(Collection<?> collection) {
77      return delegate.containsAll(collection);
78    }
79  
80    @Override public boolean isEmpty() {
81      return delegate.isEmpty();
82    }
83  
84    @Override public boolean equals(Object object) {
85      return object == this || delegate.equals(object);
86    }
87  
88    private transient int hashCode;
89  
90    @Override public int hashCode() {
91      int result = hashCode;
92      return (result == 0) ? hashCode = delegate.hashCode() : result;
93    }
94  
95    @Override public String toString() {
96      return delegate.toString();
97    }
98  
99    // All callers of the constructor are restricted to <E extends Enum<E>>.
100   @Override Object writeReplace() {
101     return new EnumSerializedForm<E>(delegate);
102   }
103 
104   /*
105    * This class is used to serialize ImmutableEnumSet instances.
106    */
107   private static class EnumSerializedForm<E extends Enum<E>>
108       implements Serializable {
109     final EnumSet<E> delegate;
110     EnumSerializedForm(EnumSet<E> delegate) {
111       this.delegate = delegate;
112     }
113     Object readResolve() {
114       // EJ2 #76: Write readObject() methods defensively.
115       return new ImmutableEnumSet<E>(delegate.clone());
116     }
117     private static final long serialVersionUID = 0;
118   }
119 }